#pragma once
#ifndef BUFFER_H
#define BUFFER_H
#include "NonCopyable.h"
#include "Logger.h"
#include <cstring>
#include <string>
#include <vector>
namespace mymuduo {

// 网络库底层的缓冲区类型
// == prependable == readable == writable == 
class Buffer : public NonCopyable {
public:
    static const size_t kCheapPrepend = 8;
    static const size_t kInitialSize = 1024;

    explicit Buffer(size_t initialSize = kInitialSize) 
        : buffer_(kCheapPrepend + initialSize)
        , readerIndex_(kCheapPrepend)
        , writerIndex_(kCheapPrepend) {}

    size_t readableBytes() const {return writerIndex_ - readerIndex_;}
    size_t writableBytes() const {return buffer_.size() - writerIndex_;}
    size_t prependableBytes() const {return readerIndex_;}

    // 返回缓冲区中可读数据的起始地址
    const char* peek() const {return begin() + readerIndex_;}
    
    // 读取数据后修改指针位置
    void retrieve(size_t len) {
        if(len < readableBytes()) {
            readerIndex_ += len;
        } else if(len == readableBytes()) {
            retrieveAll();
        } else {
            LOG_FATAL("%s:%s:%d retrive error\n",__FILE__ ,__FUNCTION__, __LINE__);
        }
    }
    void retrieveAll() {
        readerIndex_ = kCheapPrepend;
        writerIndex_ = kCheapPrepend;
    }

    // buffer -> string
    std::string retrieveAllAsString() {return retrieveAsString(readableBytes());}

    std::string retrieveAsString(size_t len) {
        std::string result(peek(), len);
        retrieve(len); // 上面一句把缓冲区中可读的数据已经读取出来，这里肯定要对缓冲区进行复位操作
        return result;
    }

    // 比较 len 和可写缓冲区的大小，确保一定可写，不可写时自动扩容
    void ensureWriteableBytes(size_t len) {
        if(writableBytes() < len) {
            makeSpace(len);
        }
    }

    // 把[data,data+len]内存上的数据，添加到 writeable 缓冲区
    void append(const char* data, size_t len) {
        ensureWriteableBytes(len);
        // 从一个容器中复制元素到另一个容器，三个参数为源范围的开始和结束迭代器，以及目标范围的开始迭代器
        std::copy(data, data+len, beginWrite()); 
        writerIndex_ += len;
    }
    
    char* beginWrite() {return begin() + writerIndex_;}
    const char* beginWrite() const {return begin() + writerIndex_;}

    // 从 fd 上读取数据
    ssize_t readFd(int fd, int* saveError);
    // 通过 fd 发送数据
    ssize_t writeFd(int fd, int* saveError);

private:
    char* begin() {return &*buffer_.begin();}
    const char* begin() const {return &*buffer_.begin();}

    void makeSpace(size_t len) {
        if(writableBytes() + prependableBytes() < len + kCheapPrepend) {
            buffer_.resize(writerIndex_ + len);
        } else {
            size_t readable = readableBytes();
            std::copy(begin() + readable,
                      begin() + writerIndex_,
                      begin() + kCheapPrepend);
            readerIndex_ = kCheapPrepend;
            writerIndex_ = readerIndex_ + readable;
        }
    }

    std::vector<char> buffer_;
    size_t readerIndex_;
    size_t writerIndex_;
};

}

#endif